﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;

namespace Common.Parser
{
    public class BaseParser : IDisposable
    {
        private object data = null;
        private string dynAssemblyPath = string.Empty;
        private string parserText = string.Empty;
        private object exitObj = null;
        private Dictionary<string, byte> assemblys = new Dictionary<string, byte>();
        private Dictionary<string, byte> namespaces = new Dictionary<string, byte>();

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseParser"/> class.
        /// </summary>
        public BaseParser()
            : this(string.Empty)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseParser"/> class.
        /// </summary>
        /// <param name="parserText">解析文本.</param>
        /// </summary>
        public BaseParser(string parserText)
            : this(parserText, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseParser"/> class.
        /// </summary>
        /// <param name="parserText">解析文本.</param>
        /// <param name="data">解析对象数据.</param>
        public BaseParser(string parserText, object data)
            : this(parserText, data, null, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseParser"/> class.
        /// </summary>
        /// <param name="parserText">解析文本.</param>
        /// <param name="data">解析对象数据.</param>
        /// <param name="namespaces">名字空间列表.</param>
        /// <param name="assemblys">DLL列表.</param>
        public BaseParser(string parserText, object data, List<string> namespaces, List<string> assemblys)
        {
            this.Data = data;
            this.ParserText = parserText;
            this.AddMapping(this);
            if (namespaces != null && namespaces.Any())
            {
                namespaces.ForEach(t =>
                {
                    this.Namespaces[t] = 0;
                });
            }

            if (assemblys != null && assemblys.Any())
            {
                assemblys.ForEach(t =>
                {
                    this.Assemblys[t] = 0;
                });
            }
        }

        /// <summary>
        /// Gets or sets 解析对象数据.
        /// </summary>
        [ParserProperty]
        public virtual object Data
        {
            get { return this.data; }
            set { this.data = value; }
        }

        /// <summary>
        /// Gets or sets 解析文本.
        /// </summary>
        public virtual string ParserText
        {
            get
            {
                return this.parserText;
            }

            set
            {
                this.parserText = value;
            }
        }

        /// <summary>
        /// Gets 属性匹配列表.
        /// </summary>
        protected SortedDictionary<string, object> PropertyMaps { get; } = new SortedDictionary<string, object>();

        /// <summary>
        /// Gets 方法匹配列表.
        /// </summary>
        protected SortedDictionary<string, object> FunctionMaps { get; } = new SortedDictionary<string, object>();

        /// <summary>
        /// Gets 表达式匹配列表.
        /// </summary>
        protected SortedDictionary<string, object> ExpressionFunctionMaps { get; } = new SortedDictionary<string, object>();

        private Dictionary<string, byte> Namespaces
        {
            get
            {
                if (this.namespaces == null)
                {
                    this.namespaces = new Dictionary<string, byte>();
                }

                return this.namespaces;
            }
        }

        private Dictionary<string, byte> Assemblys
        {
            get
            {
                if (this.assemblys == null)
                {
                    this.assemblys = new Dictionary<string, byte>();
                }

                return this.assemblys;
            }
        }

        /// <summary>
        /// 获取结果函数.
        /// </summary>
        /// <param name="obj">结果对象.</param>
        [ParserFunction]
        public void Exit(object obj)
        {
            this.exitObj = obj;
        }

        /// <summary>
        /// 对象转int.
        /// </summary>
        /// <param name="obj">对象.</param>
        /// <returns>int 值.</returns>
        [ParserFunction]
        public int ToInt(object obj)
        {
            if (obj == null)
            {
                return 0;
            }

            return Convert.ToInt32(obj);
        }

        /// <summary>
        /// 解析文本的合法性.
        /// </summary>
        /// <returns>
        /// 警告信息.
        /// </returns>
        public string Parser()
        {
            var cr = this.GetCompiler(out string warningMessage);
            if (cr != null && !cr.Success)
            {
                StringBuilder sb = new StringBuilder();
                foreach (Diagnostic codeIssue in cr.Diagnostics)
                {
                    string issue = $"ID: {codeIssue.Id}, Message: {codeIssue.GetMessage()},Location: {codeIssue.Location.GetLineSpan()},Severity: {codeIssue.Severity}";
                    sb.AppendLine(issue);
                }

                throw new Exception(sb.ToString());
            }

            return warningMessage;
        }

        /// <summary>
        /// 执行文本解析.
        /// </summary>
        /// <returns>执行结果.</returns>
        public object Execute()
        {
            this.exitObj = null;
            this.Parser();
            Assembly objAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(this.dynAssemblyPath);
            Func<string, object> propertyFunc = (propertyName) =>
            {
                var element = this.GetPropertyElement(propertyName, null, null);
                return this.GetPropertyElementValue(element);
            };
            Func<string, object[], object> funcFunc = (funcName, objs) =>
            {
                var element = this.GetFunctionElement(funcName);
                return this.GetFunctionElementValue(element, objs);
            };

            var objs = this.GetDynParserConstructeParam(propertyFunc, funcFunc);
            object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.DynParser", true, BindingFlags.Public | BindingFlags.Instance, null, objs, CultureInfo.CurrentCulture, null);
            MethodInfo objMI = objHelloWorld.GetType().GetMethod("Execute");
            objMI.Invoke(objHelloWorld, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, null, CultureInfo.CurrentCulture);
            return this.exitObj;
        }

        /// <summary>
        /// 添加对象.
        /// </summary>
        /// <param name="obj">对象.</param>
        public void AddMapping(object obj)
        {
            if (obj == null)
            {
                return;
            }

            Type type = obj.GetType();
            string nameSpace = type.Namespace;
            this.namespaces[nameSpace] = 0;
            this.assemblys[type.Assembly.Location] = 0;
            foreach (PropertyInfo proInfo in type.GetProperties())
            {
                object[] attrs = proInfo.GetCustomAttributes(typeof(ParserPropertyAttribute), true);
                if (attrs.Length == 1)
                {
                    this.PropertyMaps[proInfo.Name] = obj;
                    this.DoAddNamespaceAssembly(proInfo.PropertyType, false);
                    ParserPropertyAttribute attr = attrs[0] as ParserPropertyAttribute;
                    if (!string.IsNullOrEmpty(attr.Namespaces))
                    {
                        string[] temps = attr.Namespaces.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var item in temps)
                        {
                            this.Namespaces[item] = 0;
                        }
                    }

                    if (!string.IsNullOrEmpty(attr.Assemblys))
                    {
                        string[] temps = attr.Assemblys.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var item in temps)
                        {
                            this.Namespaces[item] = 0;
                        }
                    }
                }
            }

            foreach (MethodInfo proInfo in type.GetMethods())
            {
                object[] attrs = proInfo.GetCustomAttributes(typeof(ParserFunctionAttribute), true);
                if (attrs.Length == 1)
                {
                    this.FunctionMaps[proInfo.Name] = obj;
                    this.DoAddNamespaceAssembly(proInfo.ReturnType, false);
                    var ps = proInfo.GetParameters();
                    if (ps != null && ps.Any())
                    {
                        foreach (var item in ps)
                        {
                            this.DoAddNamespaceAssembly(item.ParameterType, false);
                        }
                    }

                    ParserFunctionAttribute attr = attrs[0] as ParserFunctionAttribute;
                    if (!string.IsNullOrEmpty(attr.Namespaces))
                    {
                        string[] temps = attr.Namespaces.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var item in temps)
                        {
                            this.Namespaces[item] = 0;
                        }
                    }

                    if (!string.IsNullOrEmpty(attr.Assemblys))
                    {
                        string[] temps = attr.Assemblys.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var item in temps)
                        {
                            this.Namespaces[item] = 0;
                        }
                    }
                }

                attrs = proInfo.GetCustomAttributes(typeof(ParserExpressionFunctionAttribute), true);
                if (attrs.Length == 1)
                {
                    this.ExpressionFunctionMaps[proInfo.Name] = obj;
                    this.DoAddNamespaceAssembly(proInfo.ReturnType, false);
                    var ps = proInfo.GetParameters();
                    if (ps != null && ps.Any())
                    {
                        foreach (var item in ps)
                        {
                            this.DoAddNamespaceAssembly(item.ParameterType, false);
                        }
                    }

                    ParserExpressionFunctionAttribute attr = attrs[0] as ParserExpressionFunctionAttribute;
                    if (!string.IsNullOrEmpty(attr.Namespaces))
                    {
                        string[] temps = attr.Namespaces.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var item in temps)
                        {
                            this.Namespaces[item] = 0;
                        }
                    }

                    if (!string.IsNullOrEmpty(attr.Assemblys))
                    {
                        string[] temps = attr.Assemblys.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var item in temps)
                        {
                            this.Namespaces[item] = 0;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 注册类型.
        /// </summary>
        /// <param name="type">类型.</param>
        public void AddType(Type type)
        {
            if (type == null)
            {
                return;
            }

            this.AddNamespace(type.Namespace);
            this.AddAssembly(type.Assembly.Location);

            foreach (PropertyInfo proInfo in type.GetProperties())
            {
                this.DoAddNamespaceAssembly(proInfo.PropertyType, true);
            }
        }

        /// <summary>
        /// 注册名字空间.
        /// </summary>
        /// <param name="addNamespace">名字空间.</param>
        public void AddNamespace(string addNamespace)
        {
            if (!this.Namespaces.ContainsKey(addNamespace))
            {
                this.Namespaces[addNamespace] = 0;
            }
        }

        /// <summary>
        /// 注册DLL.
        /// </summary>
        /// <param name="addAssembly">DLL名称.</param>
        public void AddAssembly(string addAssembly)
        {
            if (!this.Assemblys.ContainsKey(addAssembly))
            {
                this.Assemblys[addAssembly] = 0;
            }
        }

        /// <summary>
        /// 销毁对象.
        /// </summary>
        public virtual void Dispose()
        {
        }

        /// <summary>
        /// 检查属性是否解析属性.
        /// </summary>
        /// <param name="propertyName">属性名称.</param>
        /// <param name="assemblys">缓存使用到的DLL.</param>
        /// <param name="namespaces">缓存名字空间.</param>
        /// <param name="propertyTypeName">缓存属性类型.</param>
        /// <returns>是否是解析属性.</returns>
        protected virtual bool CheckPropertyName(string propertyName, Dictionary<string, byte> assemblys, Dictionary<string, byte> namespaces, out string propertyTypeName)
        {
            propertyTypeName = string.Empty;
            if (string.IsNullOrEmpty(propertyName))
            {
                return false;
            }

            string temp = propertyName;
            var index = temp.IndexOf(".", StringComparison.OrdinalIgnoreCase);
            if (index != -1)
            {
                temp = propertyName.Substring(0, index);
            }

            if (this.PropertyMaps.TryGetValue(temp, out object obj))
            {
                string refP = string.Empty;
                this.GetPropertyTypeName(propertyName.Split('.'), 0, obj, assemblys, namespaces, ref refP);
                propertyTypeName = refP;

                var pro = obj.GetType().GetProperty(temp);
                if (pro != null)
                {
                    if ((pro.PropertyType.BaseType != null && pro.PropertyType.BaseType.Name == "Object") || pro.PropertyType.Name == "Object")
                    {
                        var tempObj = pro.GetValue(obj, null);
                        if (tempObj != null)
                        {
                            var type = tempObj.GetType();
                            if (type.IsGenericType)
                            {
                                string baseTypeName = type.Name.Substring(0, type.Name.Length - 2);
                                var types = type.GetGenericArguments();
                                if (types != null && types.Any())
                                {
                                    propertyTypeName = baseTypeName + "<";
                                    StringBuilder s = new StringBuilder();
                                    foreach (var item in types)
                                    {
                                        s.Append(item.Name);
                                        s.Append(",");
                                        if (namespaces != null)
                                        {
                                            namespaces[item.Namespace] = 0;
                                        }

                                        if (assemblys != null)
                                        {
                                            assemblys[item.Assembly.Location] = 0;
                                        }
                                    }

                                    s.Length--;
                                    propertyTypeName += s.ToString();
                                    propertyTypeName += ">";
                                }
                            }
                            else
                            {
                                propertyTypeName = type.Name;
                            }

                            if (namespaces != null)
                            {
                                namespaces[type.Namespace] = 0;
                            }

                            if (assemblys != null)
                            {
                                assemblys[type.Assembly.Location] = 0;
                            }
                        }
                    }
                    else
                    {
                        propertyTypeName = pro.PropertyType.Name;
                        if (namespaces != null)
                        {
                            namespaces[pro.PropertyType.Namespace] = 0;
                        }

                        if (assemblys != null)
                        {
                            assemblys[pro.PropertyType.Assembly.Location] = 0;
                        }
                    }
                }

                return true;
            }

            return false;
        }

        /// <summary>
        /// 获取属性Element.
        /// </summary>
        /// <param name="propertyName">属性名称.</param>
        /// <param name="assemblys">缓存使用到的DLL.</param>
        /// <param name="namespaces">缓存名字空间.</param>
        /// <returns>属性Element.</returns>
        protected virtual PropertyBaseElement GetPropertyElement(string propertyName, Dictionary<string, byte> assemblys, Dictionary<string, byte> namespaces)
        {
            if (this.CheckPropertyName(propertyName, assemblys, namespaces, out string proTypeName))
            {
                return new PropertyBaseElement(propertyName, proTypeName);
            }

            return null;
        }

        /// <summary>
        /// 获取属性Element值.
        /// </summary>
        /// <param name="propertyElement">属性Element对象.</param>
        /// <returns>值.</returns>
        protected virtual object GetPropertyElementValue(PropertyBaseElement propertyElement)
        {
            if (propertyElement == null)
            {
                return null;
            }

            string proName = propertyElement.PropertyName;
            if (string.IsNullOrEmpty(proName))
            {
                return null;
            }

            var proNames = proName.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            if (proNames.Any() && this.PropertyMaps.TryGetValue(proNames[0], out object obj))
            {
                return this.DoGetPropertyValue(proNames, 0, obj);
            }

            return null;
        }

        /// <summary>
        ///  检查函数是否需解析.
        /// </summary>
        /// <param name="functionName">函数名称.</param>
        /// <param name="functionReturnTypeName">函数返回值类型.</param>
        /// <param name="funType">函数类型.</param>
        /// <returns>是否需要解析.</returns>
        protected virtual bool CheckFunctionName(string functionName, out string functionReturnTypeName, out int funType)
        {
            functionReturnTypeName = string.Empty;
            funType = 0;
            if (string.IsNullOrEmpty(functionName))
            {
                return false;
            }

            string temp = functionName;
            if (this.FunctionMaps.TryGetValue(temp, out object obj))
            {
                var pro = obj.GetType().GetMethod(temp);
                if (pro != null && string.Compare(pro.ReturnType.Name, "object", true) != 0)
                {
                    functionReturnTypeName = pro.ReturnType.Name;
                }

                return true;
            }

            if (this.ExpressionFunctionMaps.TryGetValue(temp, out obj))
            {
                var pro = obj.GetType().GetMethod(temp);
                funType = 1;
                if (pro != null && string.Compare(pro.ReturnType.Name, "object", true) != 0)
                {
                    functionReturnTypeName = pro.ReturnType.Name;
                }

                return true;
            }

            return false;
        }

        /// <summary>
        /// 获取函数单元.
        /// </summary>
        /// <param name="functionName">函数单元.</param>
        /// <returns>单元.</returns>
        protected virtual FunctionBaseElement GetFunctionElement(string functionName)
        {
            if (this.CheckFunctionName(functionName, out string returnTypeStr, out int funType))
            {
                if (funType == 1)
                {
                    return new FunctionExpressionElement(functionName, returnTypeStr);
                }

                return new FunctionBaseElement(functionName, returnTypeStr);
            }

            return null;
        }

        /// <summary>
        /// 获取函数单元值.
        /// </summary>
        /// <param name="functionElement">函数单元.</param>
        /// <param name="objs">对象列表.</param>
        /// <returns>值.</returns>
        protected virtual object GetFunctionElementValue(FunctionBaseElement functionElement, object[] objs)
        {
            if (functionElement == null)
            {
                return null;
            }

            string proName = functionElement.FunctionName;
            if (string.IsNullOrEmpty(proName))
            {
                return null;
            }

            if (this.FunctionMaps.TryGetValue(proName, out object obj))
            {
                MethodInfo objMI = obj.GetType().GetMethod(proName);
                if (objMI != null)
                {
                    return objMI.Invoke(obj, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, objs, CultureInfo.CurrentCulture);
                }
            }

            return null;
        }

        /// <summary>
        /// 获取解析构造的参数.
        /// </summary>
        /// <param name="propertyFunc">属性.</param>
        /// <param name="funcFunc">函数.</param>
        /// <returns>参数对象.</returns>
        protected virtual object[] GetDynParserConstructeParam(Func<string, object> propertyFunc, Func<string, object[], object> funcFunc)
        {
            return new object[] { propertyFunc, funcFunc };
        }

        /// <summary>
        /// 获取动态表达式解析对象类型.
        /// </summary>
        /// <returns>类型.</returns>
        protected virtual string GetDynExpressionParserType()
        {
            return string.Empty;
        }

        private object DoGetPropertyValue(List<string> proNames, int index, object obj)
        {
            if (proNames.Count - 1 == index)
            {
                string p1 = proNames[index];
                var pro1 = obj.GetType().GetProperty(p1);
                if (pro1 != null)
                {
                    return pro1.GetValue(obj, null);
                }

                return null;
            }

            string p = proNames[index];
            var pro = obj.GetType().GetProperty(p);
            if (pro != null)
            {
                return this.DoGetPropertyValue(proNames, index + 1, pro.GetValue(obj, null));
            }

            return null;
        }

        private string Hash_MD5_32(string word, bool toUpper = true)
        {
            var md5csp = System.Security.Cryptography.MD5.Create();
            try
            {
                byte[] bytValue = System.Text.Encoding.UTF8.GetBytes(word);
                byte[] bytHash = md5csp.ComputeHash(bytValue);
                md5csp.Clear();

                ////根据计算得到的Hash码翻译为MD5码
                string hashStr = string.Empty;
                for (int counter = 0; counter < bytHash.Length; counter++)
                {
                    long i = bytHash[counter] / 16;
                    string tempStr;
                    if (i > 9)
                    {
                        tempStr = ((char)(i - 10 + 0x41)).ToString();
                    }
                    else
                    {
                        tempStr = ((char)(i + 0x30)).ToString();
                    }

                    i = bytHash[counter] % 16;
                    if (i > 9)
                    {
                        tempStr += ((char)(i - 10 + 0x41)).ToString();
                    }
                    else
                    {
                        tempStr += ((char)(i + 0x30)).ToString();
                    }

                    hashStr += tempStr;
                }

                ////根据大小写规则决定返回的字符串
                return toUpper ? hashStr : hashStr.ToLower();
            }
            finally
            {
                md5csp.Dispose();
            }
        }

        private EmitResult GetCompiler(out string warningMessage)
        {
            warningMessage = null;
            var s = Hash_MD5_32(this.ParserText);
            var p = System.AppContext.BaseDirectory;
            if (string.IsNullOrEmpty(p))
            {
                p = Directory.GetCurrentDirectory();
            }

            var path = Path.Combine(p, "parserDll");
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            string fileName = s + ".dll";
            this.dynAssemblyPath = Path.Combine(path, fileName);
            if (File.Exists(this.dynAssemblyPath))
            {
                return null;
            }

            string parserText = this.GetParserText(out Dictionary<string, byte> assemblys, out warningMessage);

            var tree = SyntaxFactory.ParseSyntaxTree(parserText);

            List<MetadataReference> metadataReferences = new List<MetadataReference>();

            var references = AppDomain.CurrentDomain.GetAssemblies().Where(t => !t.IsDynamic).Select(x => MetadataReference.CreateFromFile(x.Location));
            metadataReferences.AddRange(references);

            if (this.Assemblys.Any())
            {
                foreach (var item in this.Assemblys.Keys)
                {
                    var temp = MetadataReference.CreateFromFile(item);
                    metadataReferences.Add(temp);
                }
            }

            if (assemblys != null && assemblys.Any())
            {
                foreach (var item in assemblys.Keys)
                {
                    if (!this.Assemblys.ContainsKey(item))
                    {
                        var temp = MetadataReference.CreateFromFile(item);
                        metadataReferences.Add(temp);
                    }
                }
            }

            var compilation = CSharpCompilation.Create(fileName)
              .WithOptions(
                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
              .AddReferences(metadataReferences.ToArray())
              .AddSyntaxTrees(tree);
            var compilerResult = compilation.Emit(this.dynAssemblyPath);
            return compilerResult;
        }

        private string GetParserText(out Dictionary<string, byte> assemblys, out string warningMessage)
        {
            warningMessage = null;
            assemblys = new Dictionary<string, byte>();
            Dictionary<string, byte> namespaces = new Dictionary<string, byte>();

            string parserText = this.ParserText;
            if (string.IsNullOrEmpty(parserText))
            {
                throw new Exception("请填写脚本");
            }

            StringBuilder errorBuilder = new StringBuilder();
            StringBuilder warningBuilder = new StringBuilder();

            var expType = this.GetDynExpressionParserType();
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("namespace DynamicCodeGenerate");
            sb.AppendLine("{");
            sb.AppendLine("      public class DynParser ");
            sb.AppendLine("      {");
            sb.AppendLine("Func<string, object> propertyFunc { get; set; }");
            sb.AppendLine("Func<string, object[], object> funcFunc { get; set; }");
            if (!string.IsNullOrEmpty(expType))
            {
                sb.AppendLine("Func<string, Expression<Func<" + expType + ", bool>>,object[],object> expreFunc { get; set; }");
            }

            sb.AppendLine("public DynParser(Func<string, object> propertyFunc, Func<string, object[], object> funcFunc" +
                (string.IsNullOrEmpty(expType) ? string.Empty : (",Func<string, Expression<Func<" + expType + ", bool>>,object[],object> expreFunc")) + ")");
            sb.AppendLine("{");
            sb.AppendLine("this.propertyFunc = propertyFunc;");
            sb.AppendLine("this.funcFunc = funcFunc;");
            if (!string.IsNullOrEmpty(expType))
            {
                sb.AppendLine("this.expreFunc = expreFunc;");
            }

            sb.AppendLine("}");
            sb.AppendLine("public void Execute()");
            sb.AppendLine("{");

            StringBuilder funcBuilder = new StringBuilder();
            string rs = string.Empty;
            string funcName = string.Empty;
            int type = -1;
            foreach (var c in parserText)
            {
                switch (c)
                {
                    case '[':
                        sb.Append(rs);
                        rs = string.Empty;
                        funcName = string.Empty;
                        type = 0;
                        break;
                    case ']':
                        var propertyElement = this.GetPropertyElement(rs, assemblys, namespaces);
                        if (propertyElement != null)
                        {
                            if (!string.IsNullOrEmpty(propertyElement.PropertyTypeName))
                            {
                                sb.Append("((" + propertyElement.PropertyTypeName + ")propertyFunc(\"" + rs + "\"))");
                            }
                            else
                            {
                                sb.Append("propertyFunc(\"" + rs + "\")");
                            }
                        }
                        else
                        {
                            sb.Append("[" + rs + "]");
                            warningBuilder.AppendLine("无效属性[" + rs + "]");
                        }

                        type = -1;
                        rs = string.Empty;
                        funcName = string.Empty;
                        break;
                    case '(':
                        var funcElement = this.GetFunctionElement(funcName);
                        if (funcElement != null)
                        {
                            if (funcElement is FunctionExpressionElement)
                            {
                                bool isReturnVoid = string.IsNullOrEmpty(funcElement.FunctionReturnTypeName) ||
                                     string.Compare(funcElement.FunctionReturnTypeName, "void", true) == 0;
                                funcBuilder.Append(" public " + (isReturnVoid ? "void " : "object ") + funcName + "(Expression<Func<" + expType + ", bool>> predicate,object[] objs=null)");
                                sb.Append(Environment.NewLine);
                                funcBuilder.Append(" {");
                                sb.Append(Environment.NewLine);
                                funcBuilder.Append(" expreFunc(\"" + funcName + "\",predicate,objs);");
                                sb.Append(Environment.NewLine);
                                funcBuilder.Append(" }");
                                sb.Append(Environment.NewLine);
                            }
                            else
                            {
                                bool isReturnVoid = string.IsNullOrEmpty(funcElement.FunctionReturnTypeName) ||
                                    string.Compare(funcElement.FunctionReturnTypeName, "void", true) == 0;

                                funcBuilder.Append(" public " + (isReturnVoid ? "void " : funcElement.FunctionReturnTypeName) + " " + funcName + "(params object[] obj)");
                                sb.Append(Environment.NewLine);
                                funcBuilder.Append(" {");
                                sb.Append(Environment.NewLine);
                                funcBuilder.Append((isReturnVoid ? string.Empty : ("return (" + funcElement.FunctionReturnTypeName + ")")) + " funcFunc(\"" + funcName + "\",obj);");
                                sb.Append(Environment.NewLine);
                                funcBuilder.Append(" }");
                                sb.Append(Environment.NewLine);
                            }
                        }

                        sb.Append(rs);
                        rs = string.Empty;
                        funcName = string.Empty;
                        sb.Append(c);
                        type = 2;
                        break;
                    case ' ':
                    case ',':
                    case '\n':
                    case ';':
                    case '.':
                    case '=':
                        rs += c;
                        funcName = string.Empty;
                        type = 2;
                        break;
                    default:
                        if (type == -1)
                        {
                            sb.Append(c);
                            funcName += c;
                        }
                        else
                        {
                            rs += c;
                            funcName += c;
                        }

                        break;
                }
            }

            sb.Append(rs);

            sb.AppendLine("          }");

            sb.AppendLine(funcBuilder.ToString());

            sb.AppendLine("      }");
            sb.AppendLine("}");

            if (errorBuilder.Length != 0)
            {
                throw new Exception(errorBuilder.ToString());
            }

            if (warningBuilder.Length > 0)
            {
                warningMessage = warningBuilder.ToString();
            }

            StringBuilder usingBuilder = new StringBuilder();
            usingBuilder.AppendLine("using System;");
            usingBuilder.AppendLine("using System.Collections.Generic;");
            usingBuilder.AppendLine("using System.Linq;");
            usingBuilder.AppendLine("using System.Linq.Expressions;");
            usingBuilder.AppendLine("using System.Reflection;");
            usingBuilder.AppendLine("using System.Text;");

            if (this.Namespaces.Any())
            {
                foreach (var item in this.Namespaces.Keys)
                {
                    usingBuilder.AppendLine("using " + item + ";");
                }
            }

            if (namespaces.Any())
            {
                foreach (var item in namespaces.Keys)
                {
                    if (!this.Namespaces.ContainsKey(item))
                    {
                        usingBuilder.AppendLine("using " + item + ";");
                    }
                }
            }

            return usingBuilder.ToString() + sb.ToString();
        }

        private void DoAddNamespaceAssembly(Type type, bool isGetChild)
        {
            if (type.IsClass && !type.FullName.Contains("System.String"))
            {
                if (type.IsGenericType)
                {
                    Type[] types = type.GetGenericArguments();
                    if (types != null && types.Any())
                    {
                        foreach (var item in types)
                        {
                            if (isGetChild)
                            {
                                this.AddType(item);
                            }
                            else
                            {
                                this.AddNamespace(item.Namespace);
                                this.AddAssembly(item.Assembly.Location);
                            }
                        }
                    }
                }
                else
                {
                    if (isGetChild)
                    {
                        this.AddType(type);
                    }
                    else
                    {
                        this.AddNamespace(type.Namespace);
                        this.AddAssembly(type.Assembly.Location);
                    }
                }
            }
        }

        private void GetPropertyTypeName(string[] ps, int index, object obj, Dictionary<string, byte> assemblys, Dictionary<string, byte> namespaces, ref string propertyTypeName)
        {
            var pro = obj.GetType().GetProperty(ps[index]);
            if (pro != null)
            {
                if (index < ps.Length - 1)
                {
                    var tempObj1 = pro.GetValue(obj, null);
                    this.GetPropertyTypeName(ps, index + 1, tempObj1, assemblys, namespaces, ref propertyTypeName);
                }
                else
                {
                    if ((pro.PropertyType.BaseType != null && pro.PropertyType.BaseType.Name == "Object") || pro.PropertyType.Name == "Object")
                    {
                        var tempObj = pro.GetValue(obj, null);
                        if (tempObj != null)
                        {
                            var type = tempObj.GetType();
                            if (type.IsGenericType)
                            {
                                string baseTypeName = type.Name.Substring(0, type.Name.Length - 2);
                                var types = type.GetGenericArguments();
                                if (types != null && types.Any())
                                {
                                    propertyTypeName = baseTypeName + "<";
                                    StringBuilder s = new StringBuilder();
                                    foreach (var item in types)
                                    {
                                        s.Append(item.Name);
                                        s.Append(",");
                                        if (namespaces != null)
                                        {
                                            namespaces[item.Namespace] = 0;
                                        }

                                        if (assemblys != null)
                                        {
                                            assemblys[item.Assembly.Location] = 0;
                                        }
                                    }

                                    s.Length--;
                                    propertyTypeName += s.ToString();
                                    propertyTypeName += ">";
                                }
                            }
                            else
                            {
                                propertyTypeName = type.Name;
                            }

                            if (namespaces != null)
                            {
                                namespaces[type.Namespace] = 0;
                            }

                            if (assemblys != null)
                            {
                                assemblys[type.Assembly.Location] = 0;
                            }
                        }
                    }
                    else
                    {
                        propertyTypeName = pro.PropertyType.Name;
                        if (namespaces != null)
                        {
                            namespaces[pro.PropertyType.Namespace] = 0;
                        }

                        if (assemblys != null)
                        {
                            assemblys[pro.PropertyType.Assembly.Location] = 0;
                        }
                    }
                }
            }
        }
    }
}
